package ewa.memory.api;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class Manager {
	private int rows, cols;
	private int pairs;
	private int foundPairs;
	private long startTime;
	private long endTime;
	private List<List<Card>> cards;
	private int tries;
	
	private Card firstUncovered, secondUncovered;
	
	public static enum State {
		START, ONE_UNCOVERED, MISMATCH, END;
	}
	
	private State state;
	
	public static List<Card> getDefaultCards() {
		String[] cardNames = { "Muse", "", "Radiohead", "", "", "", "Mars", "" };
		
		List<Card> cards = new ArrayList<Card>();
		for (int i = 0; i < cardNames.length; i++) {
			Card c = new Card();
			c.setShown(false);
			c.setImgURL("img/card_images/card" + (i+1) + ".jpg");
			c.setName(cardNames[i]);
			
			cards.add(c);
		}
		
		return cards;
	}
	
	public void init(List<Card> images, int rows, int cols) {
		state = State.START;
		
		cards = new ArrayList<List<Card>>(rows);
		this.rows = rows;
		this.cols = cols;
		int size = rows * cols;
		pairs = size / 2;
		foundPairs = 0;
		
		startTime = System.currentTimeMillis();
		endTime = 0;
		
		// check the amount of images
		if( images.size() < pairs ) {
			throw new IllegalArgumentException("Too many cells requested for available images");
		}
		else {
			images = images.subList(0, pairs);
		}
		
		// double the images and shuffle it
		for (Card c : new ArrayList<Card>(images)) {
			images.add(c.clone());
		}
		Collections.shuffle(images);
		
		// create cards matrix
		Iterator<Card> itFiles = images.iterator();
		while (itFiles.hasNext()) {
			List<Card> row = new ArrayList<Card>();
			for (int i = 0; i < cols; i++) {
				row.add(itFiles.next());
			}
			cards.add(row);
		}
	}
	
	public int getRows() {
		return rows;
	}

	public void setRows(int rows) {
		this.rows = rows;
	}

	public int getCols() {
		return cols;
	}

	public void setCols(int cols) {
		this.cols = cols;
	}
	
	public int getFoundPairs() {
		return foundPairs;
	}
	
	public int getRemainingPairs() {
		return pairs - foundPairs;
	}
	
	public long getPlayTime() {
		if(endTime == 0)
			return System.currentTimeMillis() - startTime;
		else
			return endTime - startTime;
	}
	
	public int getTries() {
		return tries;
	}

	public List<List<Card>> getCards() {
		return cards;
	}

	public void setCards(List<List<Card>> cards) {
		this.cards = cards;
	}
	
	public State getState() {
		return state;
	}

	public Card getFirstUncovered() {
		return firstUncovered;
	}

	public Card getSecondUncovered() {
		return secondUncovered;
	}

	public Card getCard(int i, int j) {
		return cards.get(i).get(j);
	}
	
	public boolean isShown(int i, int j) {
		return getCard(i,j).isShown();
	}
	
	public boolean allUncovered() {
		for (List<Card> row : getCards()) {
			for (Card c : row) {
				if (!c.isShown()) {
					return false;
				}
			}
		}
		return true;
	}
	
	/**
	 * Tries to uncover the card at (i,j).
	 * @param i row
	 * @param j column
	 */
	public void uncover(int i, int j) {
		switch (state) {
		case START:
			firstUncovered = getCard(i, j);
			firstUncovered.setShown(true);
			state = State.ONE_UNCOVERED;
			break;
		case ONE_UNCOVERED:
			secondUncovered = getCard(i, j);
			secondUncovered.setShown(true);
			if (secondUncovered != firstUncovered
					&& secondUncovered.equals(firstUncovered)) {
				firstUncovered = null;
				secondUncovered = null;
				foundPairs++;
				if (allUncovered()) {
					endTime = System.currentTimeMillis();
					state = State.END;
				} else {
					state = State.START;
				}
			} else {
				state = State.MISMATCH;
			}
			tries++;
			break;
		case MISMATCH:
			firstUncovered.setShown(false);
			secondUncovered.setShown(false);
			firstUncovered = null;
			secondUncovered = null;
			state = State.START;
			uncover(i,j);
			break;
		case END:
			// Nothing to uncover :-)
			break;
		}
	}
}
